package com.bl.student.api.filters;

import com.bl.student.common.ApiResponseBody;
import com.bl.student.common.ApiResponseCode;
import com.bl.student.common.utils.CommonUtils;
import com.bl.student.common.utils.JSONUtil;
import com.bl.student.dao.redis.TeacherInfoDao;
import com.bl.student.dao.redis.model.TeacherInfo;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.logging.log4j.core.config.Order;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * Created by yujingyi on 2018/2/4.
 */
@Log4j2
@WebFilter(
        filterName = "teacherFilter",
        urlPatterns = "/student/apis/teacher/*",
        initParams = {
                @WebInitParam(name = "excludePath", value = "/student/apis/teacher/login," +
                        "/student/apis/teacher/get_captcha," +
                        "/student/apis/teacher/reset")
        })
@Order(2)
public class TeacherAuthFilter implements Filter {

    private static final String TOKEN_PARAM_NAME = "token";
    private static final String ACCOUNT_PARAM_NAME = "account";
    private static final String SID_PARAM_NAME = "sid";

    private static final String OMNIPOTENT_TOKEN = "woshishabi";
    private static final String OMNIPOTENT_SID = "woshinibaba";

    @Autowired
    TeacherInfoDao teacherInfoDao;

    private FilterConfig filterConfig;
    private List<String> excludePath;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        String loginExcludePaths = this.filterConfig.getInitParameter("excludePath");
        if(!Strings.isNullOrEmpty(loginExcludePaths)){
            excludePath = Splitter.on(',')
                    .omitEmptyStrings()
                    .trimResults()
                    .splitToList(loginExcludePaths);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)throws IOException, ServletException {

//        request.getServletContext()
        if (!needFilter(request, excludePath)) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = getToken((HttpServletRequest) request);
        if (Strings.isNullOrEmpty(token)) {
            denyAccess(response);
            return;
        }

        Optional<TeacherInfo> teacherInfoOptional = teacherInfoDao.getUserInfo(token);
        if (!teacherInfoOptional.isPresent()) {
            denyAccess(response);
            return;
        }
        if (teacherInfoOptional.isPresent()) {
            setUserInfo(request, teacherInfoOptional.get());
        } else {
            denyAccess(response);
            return;
        }

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

    private boolean needFilter(ServletRequest request, List<String> excludes) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        // get request url
        String reqUrl = httpServletRequest.getRequestURI().replace(
                httpServletRequest.getContextPath(), "");
        for(String path : excludes){
            if(reqUrl.startsWith(path)){
                return false;
            }
        }
        return true;
    }

    private void denyAccess(ServletResponse response) {
        denyAccess(response, ApiResponseCode.NOT_AUTHORIZED);
    }

    private void denyAccess(ServletResponse response, ApiResponseCode apiResponseCode) {
        try {
            PrintWriter outWriter = response.getWriter();
            outWriter.print(
                    JSONUtil.jsonEncode(
                            ApiResponseBody.createErrorBody(apiResponseCode.getCode(),
                                    apiResponseCode.getMsg())));
        } catch (IOException e) {
            log.error(ExceptionUtils.getRootCauseMessage(e));
        }
    }

    private Optional<Cookie> getCookie(HttpServletRequest httpServletRequest, String cookieName) {

        final Cookie[] cookies = httpServletRequest.getCookies();
        if (cookies != null && cookies.length > 0){
            for (Cookie cookie : cookies){
                if (cookieName.equals(cookie.getName())){
                    return Optional.fromNullable(cookie);
                }
            }
        }
        return Optional.absent();
    }

    private void setUserInfo(ServletRequest request, TeacherInfo teacherInfo) {
        request.setAttribute(CommonUtils.CURRENT_USER_INFO, teacherInfo);
    }

    private String getToken(HttpServletRequest httpServletRequest) {
        Optional<Cookie> cookieOptional = getCookie(httpServletRequest,"MOBILE");

        if (cookieOptional.isPresent()) {
            return cookieOptional.get().getValue();
        } else if (!Strings.isNullOrEmpty(httpServletRequest.getParameter(CommonUtils.TOKEN_PARAM))){
            return httpServletRequest.getParameter(CommonUtils.TOKEN_PARAM);
        } else {
            log.warn("no token is found, request: {}", httpServletRequest);
            return null;
        }
    }

}
